package com.kingbook.core.scripting.nodes;


import com.kingbook.common.utils.NumberUtils;
import com.kingbook.common.utils.StringUtils;
import com.kingbook.core.cache.CacheConfig;
import com.kingbook.core.cache.SQLStatementParser;
import com.kingbook.core.exception.ParamsException;
import com.kingbook.core.sql.SqlContext;
import com.kingbook.core.sql.dialect.DBDialect;
import com.google.common.collect.Lists;
import org.jdom2.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.Map;

/**
 * @Author: Bucky
 * @Date: 2019/1/2
 * @Version 1.0
 */
public class SqlNode implements Node {

    private static Logger logger = LoggerFactory.getLogger(SqlNode.class);

    private List<Node> nodeList = Lists.newArrayList();

    private String namespace;

    private String sqlId;

    private List<String> tableNames;

    private CacheConfig cacheConfig;

    public SqlNode() {
    }

    public SqlNode(String namespace, Element element, CacheConfig config) {
        this.namespace = namespace;
        this.sqlId = element.getAttributeValue("id");
        this.cacheConfig = config;
        String useCacheStr = element.getAttributeValue("useCache");
        if (StringUtils.isNotEmpty(useCacheStr)) {
            cacheConfig.setUseCache("true".equalsIgnoreCase(useCacheStr));
        }
        if (cacheConfig.isUseCache()) {
            String cacheMaxSizeStr = element.getAttributeValue("cacheMaxSize");
            if (StringUtils.isNotEmpty(cacheMaxSizeStr) && NumberUtils.isNumeric(cacheMaxSizeStr))
                cacheConfig.setCacheMaxSize(Integer.parseInt(cacheMaxSizeStr));
            String cacheDurationStr = element.getAttributeValue("cacheDuration");
            if (StringUtils.isNotEmpty(cacheDurationStr) && NumberUtils.isNumeric(cacheDurationStr)) {
                cacheConfig.setCacheDuration(Integer.parseInt(cacheDurationStr));
            }
        }
        resolve(nodeList, element);
    }

    public SqlContext getSqlContext(Map<String, ?> paramMap, Map<String, SegmentNode> segMap, DBDialect dbDialect) {
        String sql = parseValiables(getSql(nodeList, paramMap, segMap), paramMap);
        if (cacheConfig.isUseCache()) {
            tableNames = SQLStatementParser.parseTables(sql, dbDialect);
            if (cacheConfig.getCacheDuration() == 0)
                cacheConfig.setCacheDuration(tableNames.size() == 1 ? -1 : 300);
        }
        return new SqlContext(namespace,sqlId, sql, tableNames, paramMap, cacheConfig);
    }

    private String parseValiables(String sql, Map<String, ?> map) {
        if (map == null || map.isEmpty())
            return sql;

        String[] s = sql.split("\\s+");
        for (String tmp : s) {
            tmp = StringUtils.replace(tmp, "\'", "");
            String[] tt = tmp.split("\\|\\|");
            if (tt.length == 1 && tmp.startsWith(":")) {
//                getMapParam(map, tmp.substring(1));
            } else if (tt.length == 2 && tt[0].startsWith(":")) {
                sql = sql.replaceFirst(tt[0] + "\\|\\|", getMapParam(map, tt[0].substring(1)));
            } else if (tt.length == 2 && tt[1].startsWith(":")) {
                sql = sql.replaceFirst("\\|\\|" + tt[1], getMapParam(map, tt[1].substring(1)));
            } else if (tt.length == 3) {
                sql = sql.replaceFirst("\\|\\|" + tt[1] + "\\|\\|", getMapParam(map, tt[1].substring(1)));
            }
        }

        //如果是数组，先替换到sql里
        sql = replaceArray(sql, map);
        return StringUtils.replaceTab(sql);
    }

    private String replaceArray(String sql, Map<String, ?> map) {
        String p = "";
        for (String key : map.keySet()) {
            if (sql.contains(":" + key)) {
                Object o = map.get(key);
                if (o == null) {
                    logger.debug("The value of key=[" + key + "] is null.");
                    continue;
                }

                if (String[].class.equals(o.getClass())) {
                    for (String a : (String[]) o) {
                        p += "'" + a + "',";
                    }
                } else if (int[].class.equals(o.getClass())) {
                    for (int a : (int[]) o) {
                        p += a + ",";
                    }
                } else if (long[].class.equals(o.getClass())) {
                    for (long a : (long[]) o) {
                        p += a + ",";
                    }
                } else if (float[].class.equals(o.getClass())) {
                    for (float a : (float[]) o) {
                        p += a + ",";
                    }
                } else if (double[].class.equals(o.getClass())) {
                    for (double a : (double[]) o) {
                        p += a + ",";
                    }
                }

                if (p.endsWith(",")) {
                    p = p.substring(0, p.lastIndexOf(","));
                    sql = sql.replace(":" + key, p);
                }
            }
        }
        return sql;
    }


    private String getMapParam(Map<String, ?> map, String key) {
        key = StringUtils.replace(key, "\'", "");
        String p = "";
        if (map.containsKey(key) && map.get(key) != null) {
            p = map.get(key).toString();
        } else {
            throw new ParamsException("[SQL]缺少参数：" + key, logger);
        }
        return p;
    }


}
